package com.jsh.erp.service.bom;

import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.sax.handler.RowHandler;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jsh.erp.datasource.entities.*;
import com.jsh.erp.datasource.vo.MaterialExtendVo4List;
import com.jsh.erp.exception.BusinessRunTimeException;
import com.jsh.erp.service.bomMaterial.BomMaterialService;
import com.jsh.erp.service.material.MaterialService;
import com.jsh.erp.service.materialCategory.MaterialCategoryService;
import com.jsh.erp.service.materialExtend.MaterialExtendService;
import com.jsh.erp.utils.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @author zipeng
 * @date 2023/3/15
 */
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Slf4j
public class BomImportRowHandler implements RowHandler {

    private int INDEX_BARCODE = 0;
    private int INDEX_NAME = 1;
    private int INDEX_STANDARD = 2;
    private int INDEX_MODEL = 3;
    private int INDEX_CATEGORY = 4;
    private int INDEX_UNIT = 5;
    private int INDEX_COUNT = 6;

    private int ROW_INDEX_BOM = 1;
    private int ROW_INDEX_BOM_MATERIAL = 2;

    private Bom bom;
    private List<BomMaterial> materials = new ArrayList<>();

    @Resource
    private BomService bomService;

    @Resource
    private BomMaterialService bomMaterialService;

    @Resource
    private MaterialService materialService;

    @Resource
    private MaterialCategoryService materialCategoryService;

    @Resource
    private MaterialExtendService materialExtendService;

    @Override
    public void handle(int sheetIndex, long rowIndex, List<Object> rowCells) {
        if (rowIndex == ROW_INDEX_BOM) {
            handleBom(rowCells);
            return;
        }

        if (rowIndex >= ROW_INDEX_BOM_MATERIAL) {
            handleBomMaterial(rowCells);
            return;
        }
    }

    private void handleBom(List<Object> rowCells) {
        this.bom = row2Bom(rowCells);
    }

    private Bom row2Bom(List<Object> cells) {
        String barCode = StrUtil.trim(StrUtil.toStringOrNull(cells.get(INDEX_BARCODE)));
        String name = StrUtil.trim(StrUtil.toStringOrNull(cells.get(INDEX_NAME)));
        String standard = StrUtil.trim(StrUtil.toStringOrNull(cells.get(INDEX_STANDARD)));
        String model = StrUtil.trim(StrUtil.toStringOrNull(cells.get(INDEX_MODEL)));
        String categoryName = StrUtil.trim(StrUtil.toStringOrNull(cells.get(INDEX_CATEGORY)));
        String unit = StrUtil.trim(StrUtil.toStringOrNull(cells.get(INDEX_UNIT)));
        Long count = Long.parseLong(StrUtil.blankToDefault(StrUtil.toStringOrNull(cells.get(INDEX_COUNT)), "0"));
        Long categoryId = null;

        Bom bom = new Bom();
        bom.setBarCode(barCode);
        bom.setName(name);
        bom.setStandard(standard);
        bom.setModel(model);
        bom.setCategoryName(categoryName);
        bom.setCategoryId(categoryId);
        bom.setUnit(unit);

        return bom;
    }

    private void handleBomMaterial(List<Object> rowCells) {
        BomMaterial bomMaterial = row2BomMaterial(rowCells);
        this.materials.add(bomMaterial);
    }

    private BomMaterial row2BomMaterial(List<Object> cells) {
        String barCode = StrUtil.trim(StrUtil.toStringOrNull(cells.get(INDEX_BARCODE)));
        String name = StrUtil.trim(StrUtil.toStringOrNull(cells.get(INDEX_NAME)));
        String standard = StrUtil.trim(StrUtil.toStringOrNull(cells.get(INDEX_STANDARD)));
        String model = StrUtil.trim(StrUtil.toStringOrNull(cells.get(INDEX_MODEL)));
        String categoryName = StrUtil.trim(StrUtil.toStringOrNull(cells.get(INDEX_CATEGORY)));
        String unit = StrUtil.trim(StrUtil.toStringOrNull(cells.get(INDEX_UNIT)));
        Long count = Long.parseLong(StrUtil.blankToDefault(StrUtil.toStringOrNull(cells.get(INDEX_COUNT)), "0"));
        Long categoryId = null;

        BomMaterial bomMaterial = new BomMaterial();
        bomMaterial.setBarCode(barCode);
        bomMaterial.setName(name);
        bomMaterial.setCategoryName(categoryName);
        bomMaterial.setCategoryId(categoryId);
        bomMaterial.setUnit(unit);
        bomMaterial.setCount(count);
        bomMaterial.setStandard(standard);
        bomMaterial.setModel(model);

        return bomMaterial;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doAfterAllAnalysed() {
        List<Bom> bomsInDb = bomService.findByBarCode(bom.getBarCode());
        //查找bom物料是否存在，如果存在就设置一个到bom物料中
        if (!CollectionUtils.isEmpty(bomsInDb)) {
            Bom updateBom = this.bom;
            Bom bomInDb = bomsInDb.get(0);
            //更新属性,保留 修改的属性
            BeanUtils.copyProperties(bomInDb, updateBom, "name", "barCode", "unit", "standard", "model", "count");
            this.bom = updateBom;
        }

        //设置分类id
        if (this.bom.getCategoryId() == null) {
            String categoryName = this.bom.getCategoryName();
            Long categoryId = getCategoryId(categoryName);
            this.bom.setCategoryId(categoryId);
        }

        Material bomMaterial = new Material();
        BeanUtils.copyProperties(this.bom, bomMaterial);

        if (this.bom.getMaterialId() == null) {
            //创建
            Long materialId = getMaterialId(this.bom.getBarCode());
            if (materialId == null) {
                bomMaterial.setId(null);
                materialId = createMaterial(bomMaterial, this.bom.getBarCode());
            }
            this.bom.setMaterialId(materialId);
        } else {
            //更新对应的material
            bomMaterial.setId(this.bom.getMaterialId());
            updateMaterial(bomMaterial, this.bom.getBarCode());
        }


        if (CollectionUtils.isEmpty(this.materials)) {
            throw new BusinessRunTimeException("原料物料不能为空,请检查" + (ROW_INDEX_BOM_MATERIAL + 1) + "行 开始数据不为空");
        }

        for (BomMaterial bm : this.materials) {
            List<BomMaterial> bmsInDb = bomMaterialService.getByBomBarCode(this.bom.getId(), bm.getBarCode());
            //这里只会更新当前的这个bom对应的物料，其他一样的bom物料信息不会更新
            //TODO 更新所有Bom物料
            if (!CollectionUtils.isEmpty(bmsInDb)) {
                //已存在
                BomMaterial bmInDb = bmsInDb.get(0);
                //更新属性,保留 修改的属性
                BeanUtils.copyProperties(bmInDb, bm, "name", "barCode", "unit", "standard", "model", "count");
            }

            if (bm.getCategoryId() == null) {
                String categoryName = bm.getCategoryName();
                Long categoryId = getCategoryId(categoryName);
                bm.setCategoryId(categoryId);
            }


            //创建，更新物料
            if (bm.getMaterialId() == null) {
                Long materialId = getMaterialId(bm.getBarCode());
                if (materialId == null) {
                    Material subBomMaterial = new Material();
                    BeanUtils.copyProperties(bm, subBomMaterial);
                    subBomMaterial.setId(null);
                    materialId = createMaterial(subBomMaterial, bm.getBarCode());
                }
                bm.setMaterialId(materialId);
            } else {
                //更新
                Material subBomMaterial = new Material();
                BeanUtils.copyProperties(bm, subBomMaterial);
                subBomMaterial.setId(bm.getMaterialId());
                updateMaterial(subBomMaterial, bm.getBarCode());
            }

        }

        bomService.saveBom(bom, materials);
    }

    /**
     * 根据类别名称获取类别
     *
     * @param categoryName
     * @return
     */
    private Long getCategoryId(String categoryName) {
        if (StrUtil.isBlank(categoryName)) {
            return null;
        }
        Long categoryId = materialCategoryService.getCategoryIdByName(categoryName);
        if (categoryId == null) {
            throw new BusinessRunTimeException("无法找到该类别数据:" + categoryName);
        }
        return categoryId;
    }

    /**
     * 根据物料编码获取 原料id
     *
     * @param barCode
     * @return
     */
    private Long getMaterialId(String barCode) {
        if (StrUtil.isBlank(barCode)) {
            throw new BusinessRunTimeException("物料编码不能为空");
        }
        List<MaterialVo4Unit> materials = materialService.getMaterialByBarCode(barCode);
        if (CollectionUtils.isEmpty(materials)) {
            return null;
        }
        return materials.get(0).getId();
    }

    /**
     * 创建物料
     *
     * @param material
     * @param barCode
     * @return
     */
    private Long createMaterial(Material material, String barCode) {
        //需要新增物料
        MaterialExtend materialExtend = new MaterialExtend();
        materialExtend.setBarCode(barCode);
        materialExtend.setCommodityUnit(material.getUnit());

        JSONObject mJsonObj = (JSONObject) JSONObject.toJSON(material);

        List<MaterialExtend> mes = new ArrayList<>();
        mes.add(materialExtend);

        JSONArray meList = (JSONArray) JSONArray.toJSON(mes);
        mJsonObj.put("meList", meList);

        //存储新的原料
        materialService.insertMaterial(mJsonObj, SpringUtils.getRequest());

        return getMaterialId(barCode);
    }

    /**
     * 创建物料
     *
     * @param material
     * @param barCode
     * @return
     */
    private Long updateMaterial(Material material, String barCode) {
        //读取无聊扩展更新单位
        //不更新extends，即barcode不更新
        List<MaterialExtendVo4List> materialExtends = materialExtendService.getDetailList(material.getId());
        materialExtends.forEach(materialExtendVo4List -> {
            materialExtendVo4List.setCommodityUnit(material.getUnit());
        });
        JSONObject mJsonObj = (JSONObject) JSONObject.toJSON(material);

        JSONArray meList = (JSONArray) JSONArray.toJSON(materialExtends);
        mJsonObj.put("meList", meList);

        //更新
        log.info("Bom更新material: {}", material.toString());
        materialService.updateMaterial(mJsonObj, SpringUtils.getRequest());

        return material.getId();
    }

}
